/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package LinkerLoader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

/**
 * This class generates the linker text records.<p>
 * @author yogesh
 */
public class Linker {
    String[][] text_record; 
    
    /**
     * Converts an integer to hexadecimal, making sure that the hex value has 
     * a length of four. It will be prepended with 0's to make the length of four.
     * <p>
     * Changelog:<br> 
     * April 18 - found need for operation and coded it - Peter Dietz 
     * <p>
     * <b>Original Author:</b> Peter Dietz 
     * <p>
     * @param  int_value Value that needs to be converted to hex with four digits
     * @return string representation of int_value in four hex numbers
     */
    public String intToFourHex (int int_value){
        String hex_value = String.valueOf(Integer.toHexString(int_value));
        while(hex_value.length() < 4){
            hex_value = "0".concat(hex_value);
        }
        return hex_value;
    }    
    
    /**
     * This function converts a object file string to its corresponding array.
     * Columns are separated by pipes("|").<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 25,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * 
     * @param object_file_string A line of object file.
     * @return String[] for the line passed in input.
     */
    public String[] convObjectFileStringToArray(String object_file_string){
        int num_of_pipes=0;
        for(int index=0; index<object_file_string.length(); index++){
            if(object_file_string.toCharArray()[index]=='|'){
                num_of_pipes++;
            }
        }
        String[] object_file_array = new String[num_of_pipes+1];
        for(int index=0; index<object_file_array.length; index++){
            if(object_file_string.contains("|")){
                object_file_array[index]=object_file_string.substring(0,object_file_string.indexOf("|"));
                object_file_string = object_file_string.substring(object_file_string.indexOf("|")+1);
            }else{
                object_file_array[index]=object_file_string;
            }
        }
        return object_file_array;
    }
    
    /**
     * This function reads an object file and returns a String[][] containing only one type of records.
     * Either Header Records, or Linking Records, or Text Records, or End records.
     * Type expected for them in input is H, L, T, E respectively.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 25,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * @param file_address the address of file to be read.
     * @param type the type of record you want to read("L","H","T" or "E").
     * @return Returns a String[][] containing the desired contents.
     */
    public String[][] readFile(String file_address, String type){
        String[] file_1d_array; String[][] file_2d_array;
        String[][] blank_string = new String[0][0];
        try{
            File file = new File(file_address);
            BufferedReader br;
            int num_of_lines=0; String temp="";
            br = new BufferedReader(new FileReader(file));
            while((temp=br.readLine())!=null){
                if(temp.startsWith(type)){
                    num_of_lines++;
                }
            }
            if(num_of_lines==0){
                return blank_string;
            }
            int counter=0; file_1d_array = new String[num_of_lines];
            br = new BufferedReader(new FileReader(file));
            while((temp=br.readLine())!=null){
                if(temp.startsWith(type)){
                    file_1d_array[counter] = temp;
                    counter++;
                }
            }
            file_2d_array = new String[file_1d_array.length][convObjectFileStringToArray(file_1d_array[0]).length];
            for(int index=0; index<file_2d_array.length; index++){
                file_2d_array[index] = convObjectFileStringToArray(file_1d_array[index]);
            }
            return file_2d_array;
        }catch(Exception e){
            return blank_string;
        }
    }
    
    /**
    * The purpose of this function is to find the location counter of a desired label.<p>
    * Modified Log: None.<br>
    * Error Condition tested: None.<br>
    * Creation Date : May 26,2008.<br>
    * Original Author: Aashish Kumar.<br>
    * 
    * @param label This is the label that the caller needs the location of.
    * @return The function will return the location of label or -100 if the label is not found or is not declared as shvar.
    */
    public String getValueOfLabel(String[][] load_map, String label, int num_row){
        for(int index=0; index<num_row; index++){
            if(load_map[index][1].compareTo(label)==0 && (load_map[index][3].contentEquals("SHVAR")||load_map[index][3].contentEquals("START"))){
                return load_map[index][2];
            }
        }
        return "-100";
    }
    
    /**
     * This function is used to correct offset for type c.<p>
     * @param hex_code
     * @param start_of_program_offset
     * @param correction
     * @return
     */
    public int offsetCorrection2(String hex_code, String start_of_program_offset, int correction){
        return new LoadMap().correctionInt(hex_code)-Integer.parseInt(start_of_program_offset,16)+correction;
        //return Integer.parseInt(hex_code,16)-Integer.parseInt(start_of_program_offset,16)+correction;
    }
    
    /**
     * This function will process the arithmetic when there is only one exvar in the operand.<p>
     * Modified Log:<br>
     * May 28,2008 - Correction in compairing - Yogesh Jindal.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 26,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * @param text_record the text_records from the object file given by sp2.
     * @param load_map the load_map created by linker.
     * @param index2 the index of current line in text_records.
     * @param type the arithmetic type either + or -.
     */
    public void processArithmetic(String[][] text_record, String[][] load_map, int index2, String type, String[] file_address, int file_index){

        Linker linker_instance = new Linker();
        //int correction = offsetCorrection2(text_record[index2][3],linker_instance.readFile(file_address[file_index], "H")[0][3],new LoadMap().getOffsetLoadMap(file_address)[file_index]);
        int correction = new LoadMap().correctionInt(text_record[index2][3]);
        String value = getValueOfLabel(load_map, text_record[index2][6], load_map.length);
        int content_value=0;
        if(value.contentEquals("-100")){
            value="0000";
            Shared shared_instance = new Shared();
            shared_instance.throwError(190, text_record[index2][6],file_address,file_index,index2);
        }
        if(type.contentEquals("+")){
            content_value = correction+Integer.parseInt(value,16);
        }else if(type.contentEquals("-")){
            content_value = correction-Integer.parseInt(value,16);
        }else{
            return;
        }
        if(content_value>=0 && content_value<=Integer.parseInt("3ff",16)){
            String binary_last_bits = new IceAssembly.Convert().getBitCode(String.valueOf(content_value),11);
            text_record[index2][3] = intToFourHex(content_value);
            text_record[index2][5] = "";
            text_record[index2][6] = "";
        }else{
            Shared shared_instance = new Shared();
            shared_instance.throwError(191,"",file_address,file_index,index2);
        }

    }
    
    /**
     * This function will process the arithmetic when there are two exvar's in the operand.<p>
     * Modified Log:<br>
     * May 28,2008 - Correction in compairing - Yogesh Jindal.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 26,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * @param text_record the text_records from the object file given by sp2.
     * @param load_map the load_map created by linker.
     * @param index2 the index of current line in text_records.
     * @param type1 the arithmetic type either + or -.
     * @param type2 the arithmetic type either + or -.
     */
    public void processArithmetic(String[][] text_record, String[][] load_map, int index2, String type1, String type2, String[] file_address, int file_index ){
        String content_value="0";
        String value1 = getValueOfLabel(load_map, text_record[index2][6], load_map.length);
        String value2 = getValueOfLabel(load_map, text_record[index2][8], load_map.length);
        if(value1.contentEquals("-100")){
            value1="0000";
            Shared shared_instance = new Shared();
            shared_instance.throwError(190, text_record[index2][6],file_address,file_index,index2);
        }
        if(value2.contentEquals("-100")){
            value2="0000";
            Shared shared_instance = new Shared();
            shared_instance.throwError(190, text_record[index2][8],file_address,file_index,index2);
        }
        if(type1.contentEquals("+") && type2.contentEquals("+")){    
            content_value = intToFourHex(new LoadMap().correctionInt(text_record[index2][3])+Integer.parseInt(value1,16)+Integer.parseInt(value2,16));
        }else if(type1.contentEquals("+") && type2.contentEquals("-")){
            content_value = intToFourHex(new LoadMap().correctionInt(text_record[index2][3])+Integer.parseInt(value1,16)-Integer.parseInt(value2,16));
        }else if(type1.contentEquals("-") && type2.contentEquals("+")){
            content_value = intToFourHex(new LoadMap().correctionInt(text_record[index2][3])-Integer.parseInt(value1,16)+Integer.parseInt(value2,16));
        }else if(type1.contentEquals("-") && type2.contentEquals("-")){
            content_value = intToFourHex(new LoadMap().correctionInt(text_record[index2][3])-Integer.parseInt(value1,16)-Integer.parseInt(value2,16));
        }else{
            return;
        }
        if(content_value.compareTo("0000")>=0 && content_value.compareTo("03ff")<=0){
            text_record[index2][3] = content_value;
            text_record[index2][5] = "";
            text_record[index2][6] = "";
            text_record[index2][7] = "";
            text_record[index2][8] = "";
        }else{
            Shared shared_instance = new Shared();
            shared_instance.throwError(191,"",file_address,file_index,index2);
        }
    }
    
    /**
     * This function processes the text_record for relocation type R.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 26,2008.<br>
     * Original Author: Aashish Kumar.<br>
     * @param text_record the text_records of any one file at a time.
     * @param current_line the index of current line in text_records.
     * @param file_index the file number which is currently reading.
     * @param file_address a String[] containing the address of all the files passed to the linker.
     */
    public void processRelocationR(String[][] text_record, int current_line, int file_index, String[] file_address){
        Linker linker_instance = new Linker();
        text_record[current_line][3] = new LoadMap().offsetCorrection(text_record[current_line][3],linker_instance.readFile(file_address[file_index], "H")[0][3],new LoadMap().getOffsetLoadMap(file_address)[file_index]);
    }
    
    /**
     * This function process the text records for all the object files given to linker.
     * It converts the textrecords of sp2 to  the output of linker. It builds the linker textrecord and header record.<p>
     * Modified Log:<br>
     * May 28,2008 - function added for relocation type - Aashish Kumar.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 26,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * @param file_address
     * @param load_map
     */
    public void processTextRecord(String[] file_address,String[][] load_map){
        for(int index=0; index<file_address.length; index++){
            text_record = readFile(file_address[index], "T");
            for(int index2=0; index2<text_record.length; index2++){
                if(index2==0){
                    String module_name    = readFile(file_address[index], "H")[0][1];
                    String program_length = readFile(file_address[index], "H")[0][2];
                    String load_address   = readFile(file_address[index], "H")[0][3];
                    new Loader().addToLinkerHeaderRecord(module_name,program_length,load_address);
                }
                if(!text_record[index2][5].contentEquals("") && text_record[index2][7].contentEquals("")){
                    processArithmetic(text_record, load_map, index2, text_record[index2][5],file_address,index);
                }else if(!text_record[index2][5].contentEquals("") && !text_record[index2][7].contentEquals("")){
                    processArithmetic(text_record, load_map, index2,text_record[index2][5],text_record[index2][7],file_address,index);
                }else{
                    if(text_record[index2][4].contentEquals("R")){//no exvar...
                        processRelocationR(text_record,index2,index,file_address);
                    }
                }
                new Loader().addToLinkerTextRecord(text_record[index2][3], text_record[index2][2], readFile(file_address[index], "H")[0][1]);
            }
        }
    }
}